﻿using System;
using System.Collections.Generic;

namespace DataCenter.Share
{
    [Serializable]
    public enum TimeRepeatOperTypes
    {
        Ignore,
        Cover,
        Throw
    }

    [Serializable]
    public class TimeLine : SortedList<DateTime, TimePoint>, ICloneable
    {
        public TimeLine() : this(1) { }
        public TimeLine(int fieldCount)
        {
            this.fieldCount = fieldCount;
        }

        private int id;
        private string name;
        private DateTime time;
        private int type;
        private int fieldCount;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public DateTime Time
        {
            get { return time; }
            set { time = value; }
        }

        public int Type
        {
            get { return type; }
            set { type = value; }
        }

        public int FieldCount
        {
            get { return fieldCount; }
        }

        public DateTime GetFirstTime()
        {
            if (this.Count == 0)
                return Utils.EMPTY_TIME;
            return this.Keys[0];
        }
        public DateTime GetLastTime()
        {
            if (this.Count == 0)
                return Utils.EMPTY_TIME;
            return this.Keys[this.Count - 1];
        }

        public void Add(TimePoint value)
        {
            Add(value, TimeRepeatOperTypes.Ignore);
        }
        public void Add(TimePoint value, TimeRepeatOperTypes timeRepeatOperType)
        {
            if (value.Time.Date != time.Date)
                throw new ArgumentException("TimePoint 的日期和 TimeLine 的日期不相同");
            if (this.ContainsKey(value.Time))
            {
                switch (timeRepeatOperType)
                {
                    case TimeRepeatOperTypes.Ignore: return;
                    case TimeRepeatOperTypes.Cover: break;
                    case TimeRepeatOperTypes.Throw:
                        throw new InvalidOperationException("时间点\"" + value.Time + "\"已经存在");
                }
            }
            this.Add(value.Time, value);
        }
        public float GetValue(int fieldIndex, DateTime time)
        {
            float fValue = float.NaN;
            if (this.Count > 0)
            {
                if (this.ContainsKey(time))
                    fValue = this[time].Values[fieldIndex].Value;
                else if (time < this.Keys[0])
                    fValue = this.Values[0].Values[fieldIndex].Value;
                else if (time > this.Keys[this.Count - 1])
                    fValue = this.Values[this.Count - 1].Values[fieldIndex].Value;
                else
                {
                    for (int i = 1; i < this.Count; i++)
                    {
                        TimePoint prevPoint = this.Values[i - 1];
                        TimePoint nextPoint = this.Values[i];
                        if (time > prevPoint.Time)
                        {
                            if (time < nextPoint.Time)
                            {
                                double x1 = prevPoint.Time.Ticks,
                                       x2 = nextPoint.Time.Ticks,
                                       y1 = prevPoint.Values[fieldIndex].Value,
                                       y2 = nextPoint.Values[fieldIndex].Value,
                                       x = time.Ticks;
                                double a = (y2 - y1) / (x2 - x1);
                                double b = y1 - x1 * a;
                                double y = (a * x + b);
                                return (float)y;
                            }
                        }
                    }
                }
            }
            return fValue;
        }
        public float GetStatus(int fieldIndex, DateTime time)
        {
            float fValue = float.NaN;
            if (this.Count > 0)
            {
                if (this.ContainsKey(time))
                    fValue = this[time].Values[fieldIndex].Value;
                else if (time < this.Keys[0])
                    fValue = this.Values[0].Values[fieldIndex].Value;
                else if (time > this.Keys[this.Count - 1])
                    fValue = this.Values[this.Count - 1].Values[fieldIndex].Value;
                else
                {
                    for (int i = 1; i < this.Count; i++)
                    {
                        TimePoint prevPoint = this.Values[i - 1];
                        TimePoint nextPoint = this.Values[i];
                        if (time > prevPoint.Time)
                        {
                            if (time < nextPoint.Time)
                            {
                                return prevPoint.Values[fieldIndex].Value;
                            }
                        }
                    }
                }
            }
            return fValue;
        }

        public override string ToString()
        {
            string str = "";
            if (!string.IsNullOrEmpty(name))
                str = name;
            str += "(" + id + ")";
            str += "[" + time + "]";
            return str;
        }

        #region ICloneable Members

        public object Clone()
        {
            return Utils.Clone(this);
        }

        #endregion
    }
}
